#pragma once

#include "./render_select.hpp"
#include <qlib/all.h>

#include "./models.hpp"

#include "../layout/layout.hpp"
#include "../render/render.hpp"
#include "../select/select.hpp"
#include "./select_cmd.hpp"

namespace qbe::select {

template <typename TagTy, typename MeshTy, typename CellTy, typename NodeTy>
void node_update(CellTy cell, NodeTy node) {
  if (!node)
    return;
  node->clear();
  std::vector<MeshTy> in_meshs;
  for (auto [e, tag, mesh] : cell->reg.view<qlib::Tag, TagTy, MeshTy>().each()) {
    in_meshs.push_back(mesh);
  }
  if (in_meshs.size() > 0) {
    std::vector<layout::renders::Mesh> out_meshs = {};
    layout::renders::task_mesh_merge(in_meshs, &out_meshs, false);
    node->addMeshs(out_meshs);
  }
}

void select_render_init(entt::registry& reg, ecs::Commands commands, ecs::Query query) {
  auto& render_model = query.get_resource<render::Model>();
  auto& model = query.get_resource<RenderOverallModel>();

  // auto helper_group = vsg::Group::create();
  auto helper_group = render_model.select_group;
  // render_model.transform->addChild(helper_group);

  auto hover_color = vsg::vec4(0.0, 1.0, 1.0, 1.0);
  auto select_color = vsg::vec4(1.0, 1.0, 0.0, 1.0);
  auto canvas = vsg::vec2(1316.0, 847.0);

  auto gen_line_node = [&](auto& node, auto primitive, auto& color, float dash = 0, float gap = 0, bool isDash = false) {
    layout::renders::LineUniform uniform;
    uniform.color = color;
    uniform.canvas = canvas;
    uniform.dash = dash;
    uniform.gap = gap;
    uniform.isDash = isDash;
    auto material = layout::renders::LineShaderMaterial(uniform, "shaders/cell/layout-line.vert.spv", "shaders/cell/layout-line.frag.spv");
    node = layout::renders::GeoMeshNode::create();
    node->createPipe(render_model.options, material, primitive);
    helper_group->addChild(node);
  };

  auto gen_point_node = [&](auto& node, auto primitive, auto& color, int point_type = 0, float point_size = 10) {
    layout::renders::KeyPointUniform uniform;
    uniform.color = color;
    uniform.point_type = point_type;
    uniform.point_size = point_size;
    auto material =
        layout::renders::KeyPointShaderMaterial(uniform, "shaders/cell/layout-key-point.vert.spv", "shaders/cell/layout-key-point.frag.spv");
    node = layout::renders::GeoMeshNode::create();
    node->createPipe(render_model.options, material, primitive);
    helper_group->addChild(node);
  };

  gen_line_node(model.algin_select_edge_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, vsg::vec4(1.0, 0.0, 0.0, 1.0));
  gen_point_node(model.algin_select_point_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vsg::vec4(1.0, 0.0, 0.0, 1.0));

  gen_line_node(model.select_edge_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, select_color);
  gen_line_node(model.hover_edge_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, vsg::vec4(1.0, 0.0, 1.0, 1.0));

  gen_point_node(model.select_point_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, select_color);
  gen_point_node(model.hover_point_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vsg::vec4(1.0, 0.0, 1.0, 1.0));

  // 飞线
  gen_line_node(model.select_flyline_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, select_color);
  gen_line_node(model.hover_flyline_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, hover_color);

  gen_line_node(model.select_view3d_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, select_color, 50, 20, true);
  gen_line_node(model.hover_view3d_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, hover_color, 50, 20, true);

  gen_line_node(model.select_section3d_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, select_color);
  gen_line_node(model.hover_section3d_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, hover_color);

  // overall select
  {
    auto node = layout::CellMeshs::create();
    node->scene = render_model.scene;
    node->options = render_model.options;
    node->transform = render_model.transform;
    layer::Info info;
    info.setColor(1.0, 1.0, 0.0);
    node->load_layer(info);
    model.nodes = node;
    helper_group->addChild(model.nodes);
  }

  // overall hover
  {
    auto node = layout::CellMeshs::create();
    node->scene = render_model.scene;
    node->options = render_model.options;
    node->transform = render_model.transform;
    layer::Info info;
    info.setColor(0.0, 1.0, 1.0);
    node->load_layer(info);
    model.hover_nodes = node;
    helper_group->addChild(node);
  }

  // box
  gen_line_node(model.draw_box_node, VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, select_color);
};

void select_render_update(ecs::Query query, entt::registry& reg) {
  auto& model = query.get_resource<RenderOverallModel>();
  auto& select_model = query.get_resource<OverallModel>();
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& select_events = query.get_event_reader<select::Event>();
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& select_cmd = query.get_resource<SelectCmd>();
  auto& state = query.get_resource<state::State>();

  // part
  auto part_update = [&model, &cell](const auto& parts, auto& edge_node, auto& point_node) {
    qlib::Vec2dArray point_arr;
    qlib::Vec2dArray edge_arr;
    for (auto& [e, part] : parts) {
      auto fan = cell->reg.try_get<qlib::Fan::s_ptr>(e);
      auto& ps = part.points;
      auto n = ps.size();
      for (auto& [id, ok] : part.point_id_map) {
        // if (fan && id > 1 && id < n - 1) {
        //   continue;
        // }
        point_arr.push_back(ps[id % n]);
      }
      for (auto& [id, ok] : part.edge_id_map) {
        edge_arr.push_back(ps[id % n]);
        edge_arr.push_back(ps[(id + 1) % n]);
      }
    }
    edge_node->clear();
    point_node->clear();
    if (point_arr.size() > 0)
      point_node->addMesh(layout::renders::Mesh(point_arr, true));
    if (edge_arr.size() > 0)
      edge_node->addMesh(layout::renders::Mesh(edge_arr, true));
  };

  if (select_cmd.hover_part_render()) {
    part_update(select_cmd.hover_parts(), model.hover_edge_node, model.hover_point_node);
  }

  if (select_cmd.select_part_render()) {
    part_update(select_cmd.select_parts(), model.select_edge_node, model.select_point_node);
  }

  // if (select_cmd.hover_part_render()) {
  //   part_update(select_cmd.algin_hover_parts(), model.algin_hover_edge_node, model.algin_hover_point_node);
  // }

  if (select_cmd.algin_select_part_render()) {
    part_update(select_cmd.algin_select_parts(), model.algin_select_edge_node, model.algin_select_point_node);
  }

  if (select_cmd.hover_render()) {
    model.hover_nodes->clear();
    model.hover_nodes->all_update_ref_box<select::HoverTag>(cell);

    node_update<HoverTag, layout::renders::FlyLineMesh>(cell, model.hover_flyline_node);
    node_update<HoverTag, layout::renders::ViewArea3DMesh>(cell, model.hover_view3d_node);
    node_update<HoverTag, layout::renders::SectionArea3DMesh>(cell, model.hover_section3d_node);
  }

  if (select_cmd.select_render()) {
    model.nodes->clear();
    model.nodes->all_update_ref_box<select::SelectTag>(cell);

    node_update<SelectTag, layout::renders::FlyLineMesh>(cell, model.select_flyline_node);
    node_update<SelectTag, layout::renders::ViewArea3DMesh>(cell, model.select_view3d_node);
    node_update<SelectTag, layout::renders::SectionArea3DMesh>(cell, model.select_section3d_node);
  }

  select_cmd.clear_render();

  // 事件刷新
  for (auto& e : select_events) {
    if (e.code == select::Code::SelectUpdate) {
      SPDLOG_INFO("select update~");
      model.nodes->clear();
      model.nodes->all_update_ref_box<select::SelectTag>(cell);
      node_update<SelectTag, layout::renders::FlyLineMesh>(cell, model.select_flyline_node);
      node_update<SelectTag, layout::renders::ViewArea3DMesh>(cell, model.select_view3d_node);
      node_update<SelectTag, layout::renders::SectionArea3DMesh>(cell, model.select_section3d_node);
    }

    if (e.code == select::Code::SelectCancel) {
      SPDLOG_INFO("select clear~");
      model.nodes->clear();
      model.select_flyline_node->clear();
      model.select_view3d_node->clear();
      model.select_section3d_node->clear();
    }

    if (e.code == select::Code::HoverUpdate) {
      model.hover_nodes->clear();
      model.hover_nodes->all_update_ref_box<select::HoverTag>(cell);
      node_update<HoverTag, layout::renders::FlyLineMesh>(cell, model.hover_flyline_node);
      node_update<HoverTag, layout::renders::ViewArea3DMesh>(cell, model.hover_view3d_node);
      node_update<HoverTag, layout::renders::SectionArea3DMesh>(cell, model.hover_section3d_node);
    }

    if (e.code == select::Code::HoverCancel) {
      model.hover_nodes->clear();
      model.hover_flyline_node->clear();
      model.hover_view3d_node->clear();
      model.hover_section3d_node->clear();
    }

    // box
    if (e.code == select::Code::DrawBoxUpdate) {
      model.draw_box_node->updateMesh(layout::renders::Mesh(select_model.box_mesh.vertices, select_model.box_mesh.indices));
    }
    if (e.code == select::Code::DrawBoxCancel) {
      model.draw_box_node->clear();
    }

    //   // part
    //   if (e.code == select::Code::PartSelectUpdate) {
    //     part_update(select_model.select_parts, model.select_edge_node, model.select_point_node);

    //     if (select_model.algin_select_parts.size() > 1) {
    //       select_model.algin_select_parts.clear();
    //     }
    //     part_update(select_model.algin_select_parts, model.algin_select_edge_node, model.algin_select_point_node);
    //   }

    //   if (e.code == select::Code::PartSelectCancel) {
    //     model.select_edge_node->clear();
    //     model.select_point_node->clear();

    //     model.algin_select_edge_node->clear();
    //     model.algin_select_point_node->clear();
    //   }

    //   if (e.code == select::Code::PartHoverUpdate) {
    //     part_update(select_model.hover_parts, model.hover_edge_node, model.hover_point_node);
    //   }
    //   if (e.code == select::Code::PartHoverCancel) {
    //     model.hover_edge_node->clear();
    //     model.hover_point_node->clear();
    //   }
  }

  // 刻度尺
  // model.nodes->ruler_update<select::SelectTag>(cell);
};

void select_part_render_init(ecs::Query query){};

void select_part_render_update(ecs::Query query){};

void RenderSelectPlugin::build(ecs::App& app) {
  app.init_resource<RenderOverallModel>(RenderOverallModel{});

  app.add_systems<ecs::stage::Startup>(select_render_init);
  app.add_systems<ecs::stage::PostUpdate>(select_render_update);
}

}  // namespace qbe::select